#!/usr/local/bin/python2.7

from xml.etree.ElementTree import ElementTree
from xml.etree.ElementTree import Element

class TagDict(object):
    """
    A simple wrapper around the python dictionary type that allows for the
    easy saving to and loading from an xml file.

    The *filepath* instance variable is used to load and save the
    key-value pairs from.  Under default initialization, the xml file is
    formatted as follows::

        <TagDict>
            <map>
                <key>rootpath</key>
                <value>PathOfRoot</value>
            </map>
            <map>
                <key>fromroot</key>
                <value>OriginalPathFromRoot</value>
            </map>
            ...
            ...
        </TagDict>

    where 'TagDict' is the *root_tag*, 'map' is the *map_tag*, 'key' is
    the *key_tag*, and 'value' is the *value_tag* (user definable class
    attributes).

    Note that the saving is not recursive and the *TagDict* class assumes
    that its dictionary contents to be saved are objects that have simple
    string representations (e.g. strings, numbers, etc.).  Key-value pairs
    loaded from file are left as raw strings (i.e. string numbers are not
    converted into numbers).
    """
    
    def __init__(self):
        self.root_tag = 'TagDict'
        self.filepath = None
        self.map_tag = 'map'
        self.key_tag = 'key'
        self.value_tag = 'value'
        self.map = None

    def save(self):
        """
        Save the key-value pairs as a file specified by the *filepath*
        instance variable.
        """

        if self.filepath is None:
            msg = 'Filepath for TagDict instance was not specified.'
            raise Exception(msg)

        elem = Element(self.root_tag)

        for key, value in self.map.items():
            key = Element(self.key_tag)
            key.text = str(key)
            
            value = Element(self.value_tag)
            value.text = str(value)

            map = Element(self.map_tag)
            map.append(key)
            map.append(value)

            elem.append(map)

        tree = ElementTree(element = elem)
        with open(self.filepath, 'w') as myfile: tree.write(myfile)
        cleanXML(self.filepath)

    def load(self):
        """
        Load key-value pairs from the file specified by the *filepath*
        instance variable.
        """

        self._validate()

        self.map = {}
        tree = ElementTree()
        tree.parse(self.filepath)
        maps = tree.getroot()

        for map in maps:
            key = map.find(self.key_tag).text
            value = map.find(self.value_tag).text
            self.map[key] = value

    def _validate(self):
        """
        Verify the validity of the file specified by the *filepath* 
        instance attribute (e.g. file exists and uses proper tag names).
        """
        if self.filepath is None:
            msg = 'Filepath for TagDict instance was not specified.'
            raise Exception(msg)

        tree = ElementTree()
        tree.parse(self.filepath)
        maps = tree.getroot()

        if maps.tag != self.root_tag:
            msg = 'TagDict file must begin with root tag name \'' + \
                    self.root_tag + '\'.'
            raise Exception(msg)

        for map in maps:
            if map.tag != self.map_tag:
                msg = 'All map tags must be \'' + self.map_tag + '\'.'
                raise Exception(msg)

